package game.square;
import java.util.List;
import game.border.Border;

import be.kuleuven.cs.som.annotate.Basic;
import be.kuleuven.cs.som.annotate.Raw;


/**
* A class of squares involving a temperature and a humidity.
* 
* @Invar       The temperature of each square must be a valid temperature for that square.
*            	| canHaveAsTemperature(getTemparture(Temperature.CELCIUS),Temperature.CELCIUS)
* @Invar       The humidity of each square must be a valid humidity for a square.
*           	| isValidHumidity(getHumidity());
* @Invar       The maximum temperature must be a valid temperature.
*             	| canHaveAsMaximumTemperature(getMaximumTemperature(),Temperature.CELCIUS)
* @Invar       The minimum temperature must be a valid temperature.
*             	| canHaveAsMinimumTemperature(getMinimumTemperature(),Temperature.CELCIUS)
* @Invar       The weight for weighted average of temperatures must be a valid number.
*          	| isValidConstantForWeightedAverageOfTemperature(
*           	         getConstantForWeightedAverageOfTemperature)
* @Invar       The increment size for heat damage must be a valid number.
*    			| isValidIncrementSizeHeatDamage(getIncrementSizeHeatDamage(Temperature.CELCIUS))
* @Invar       The threshold temperature for heat damage must be a valid temperature.
*              | isValidThresholdHeatDamageTemperature(
*                        	getThresholdHeatDamageTemperature(Temperature.CELCIUS),
*              			Temperature.CELCIUS)
* @Invar       The border has to be a valid border.
*              | isValidBorder(getBorder(for(All directions)))
* @Invar		The square has to have a proper border at all times.
* 				|	hasProperBorder.
*              
* @version     1.0
* @author      Dries Liebens 
*   			Loic Vercruysse
*/


public interface SquareInterface {


	        /**
	         * basic inspector returning the state of the square. 
	         */
	        @Basic @Raw
	        public abstract boolean isTerminated();
	        
	        /**
	         * method terminating the square.
	         * 
	         * @Post	All the borders the square contains are terminated, 
	         * 			if the square was not yet terminated.
	         * 			|	if(!isTerminated())
	         *        	|		forEach border in getBorders():
	         *        	|		border.isTerminated() == true;
	         * @Post	the square will be terminated, if it was not terminated yet.
	         * 			|	if(!isTerminated())
	         * 			|		isTerminated() == true;
	         */
	        public abstract void terminate();
	        	
	        /**
	         * Checks whether the given temperature scale is a valid temperature scale
	         * for a square.
	         * 
	         * @param	scale
	         *          The temperature scale to check.   
	         * @return  True if the temperature scale is Celcius, Fahrenheit or Kelvin.
	         *          | result == (scale == Temperature.CELCIUS) 
	         *          |   			|| (scale == Temperature.FahrenHeit)
	         *          |               || (scale == Temperature.Kelvin)
	         */
	        @Raw
	        public abstract boolean isValidTemperatureScale(Temperature scale);
	        
	        /**
	         * Returns the temperature in the preferred scale of this square.
	         * 
	         * @param	scale
	         *          The scale in which the temperature is expressed in.
	         */
	        @Basic @Raw
	        public abstract double getTemperature(Temperature scale) ;
	        
	        /**
	         * Sets the given temperature as the temperature.
	         * 
	         * @param	temperature
	         *          The temperature in the preferred scale to set.
	         * @param   scale
	         *          The scale in which the temperature is expressed in.
	         * @post    The temperature is the same as the given temperature.
	         *          | new.getTemperature(scale) == temperature
	         * @throws  IllegalArgumentException
	         *          The temperature is not valid.
	         *          | !isValidTemperature(temperature,scale)
	         * @throws  IllegalArgumentException
	         *          The temperature scale is not valid.
	         *          | !isValidTemperatureScale(scale)
	         */
	        @Raw
	        public abstract void setTemperature(double temperature,Temperature scale);
	        
	        /**
	         * Checks whether this square can have the given temperature as temperature.
	         * 
	         * @param	temperature
	         *          The temperature in the preferred scale to check.
	         * @param   scale
	         *          The scale in which the temperature is expressed in.
	         * @return  True if the temperature is higher or equal to the minimum temperature
	         *          and lower or equal to the maximum temperature.
	         *          | result == temperature <= getMaximumTemperature(scale))
	         *          |     		&& (temperature >= getMinimumTemperature(scale))
	         */
	        public abstract boolean canHaveAsTemperature(double temperature,Temperature scale);

	        /**
	         * Returns the maximum temperature in the preferred scale of this square.
	         * 
	         * @param	scale
	         *          The scale in which the temperature is expressed in.
	         */
	        @Basic @Raw
	        public abstract double getMaximumTemperature(Temperature scale);
	        
	        /**
	         * Sets the given temperature as maximum temperature.
	         * 
	         * @param	maximumTemperature
	         *          The maximum temperature in the preferred scale to set.
	         * @param   scale
	         *          The scale in which the temperature is expressed in.
	         * @post    The maximum temperature is the same as the given maximum temperature.
	         *          | new.getMaximumTemperature(scale) == maximumTemperature
	         * @throws  IllegalArgumentException
	         *          The maximum temperature is not valid.
	         *          | !isValidMaximumTemperature(maximumTemperature,scale)
	         * @throws  IllegalArgumentException
	         *          The temperature scale is not valid.
	         *          | !isValidTemperatureScale(scale)
	         */
	        @Raw
	        public abstract void setMaximumTemperature(double maximumTemperature,Temperature scale) throws IllegalArgumentException;
	        
	        /**
	         * Checks whether this square can have the given temperature as maximum temperature.
	         * 
	         * @param	maximumTemperature
	         *          The temperature in the preferred scale to check.
	         * @param   scale
	         *          The scale in which the temperature is expressed in.
	         * @return  True if maximumTemperature is higher or equal then the minimum temperature
	         *          and maximumTemperature is higher or equal then the current temperature
	         *          | result == ( (maximumTemperature >= getMinimumTemperature(scale)) 
	         *          |         	&& (maximumTemperature >= getTemperature(scale)) )
	         */
	        public abstract boolean canHaveAsMaximumTemperature(double maximumTemperature,Temperature scale);
	        
	        /**
	         * Returns the minimum temperature in the preferred scale of this square.
	         * 
	         * @param 	scale
	         *          The scale in which the temperature is expressed in.
	         */
	        @Basic @Raw
	        public abstract double getMinimumTemperature(Temperature scale);

	        /**
	         * Sets the given temperature as minimum temperature.
	         * 
	         * @param	minimumTemperature
	         *          The minimum temperature in the preferred scale to set.
	         * @param   scale
	         *          The scale in which the temperature is expressed in.
	         * @post    The minimum temperature is the same as the given minimum temperature.
	         *          | new.getMinimumTemperature(scale) == minimumTemperature
	         * @throws  IllegalArgumentException
	         *          The minimum temperature is not valid.
	         *          | !isValidMinimumTemperature(minimumTemperature,scale)
	         * @throws  IllegalArgumentException
	         *          The temperature scale is not valid.
	         *          | !isValidTemperatureScale(scale)
	         */
	        @Raw
	        public abstract void setMinimumTemperature(double minimumTemperature,Temperature scale);
	        
	        /**
	         * Checks whether this square can have the given temperature as minimum temperature.
	         * 
	         * @param 	minimumTemperature
	         *          The temperature in the preferred scale to check.
	         * @param   scale
	         *          The scale in which the temperature is expressed in.
	         * @return  True if minimumTemperature is lower or equal then the maximum temperature
	         *          and minimumTemperature is lower or equal then the current temperature
	         *          and minimumTemperture is higher then 0 Kelvin.
	         *          | result == ( (minimumTemperature <= getMaximumTemperature(scale)) 
	         *          |       		&& (minimumTemperature <= getTemperature(scale)) 
	         *          |               && (minimumTemperature >= Temperature.KELVIN.convertTo(0,scale) )
	         */
	        public abstract boolean canHaveAsMinimumTemperature(double minimumTemperature,Temperature scale);

	        /**
	         * Returns the humidity in percents of this square.
	         */
	        @Basic @Raw
	        public abstract double getHumidity() ;
	        
	        /**
	         * Sets a valid humidity as humidity of this square.
	         * 
	         * @param	humidity
	         *          The humidity to set.
	         * @pre     The given humidity must be a valid percentage.
	         *          | isValidHumidity(humidity)
	         * @post    The humidity of this square is & valid humidity
	         *          | isValidHumidity(new.getHumidity()) 
	         */
	        @Raw
	        public abstract void setHumidity(double humidity) ;
	        
	        /**
	         * Checks whether this square can have the given humidity as humidity.
	         * 
	         * @param 	humidity
	         *          The humidity to check.
	         * @return  True if humidity is equal or lower then 100 and humidity is equal or higher then 0,
	         *          humidity may also have maximum 2 numbers after the comma.
	         *          | result == ( (humidity >= 0) && (humidity <= 100) 
	         *          |          	&& (humidity*100)%1 == 0) )
	         */
	        @Raw
	        public abstract boolean isValidHumidity(double humidity) ;
	        
	        /**
	         * Calculates the rust damage due the humidity of this square.
	         * 
	         * @return 	The humidity is first substract by 30 and then devided by 7.
	         *          | result == (getHumidity() - 30) / 7
	         */
	        public abstract int calculateRustDamage() ;
	        
	        /**
	         * Returns the threshold for heat damage in the preferred scale for squares.
	         * 
	         * @param	scale
	         *          The scale in which the temperature is expressed in.
	         * @throws  IllegalArgumentException
	         *          The temperature scale is not valid.
	         *          | !isValidTemperatureScale(scale)
	         */
	        @Basic @Raw
	        public abstract double getThresholdHeatDamageTemperature(Temperature scale);
	        
	        /**
	         * Sets the threshold for heat damage in the preferred scale for squares.
	         * 
	         * @param	thresholdHeatDamageTemperature
	         *          The temperature to set as threshold for heat damage in the preferred scale.
	         * @param   scale
	         *          The scale in which the temperature is expressed in.
	         * @post    The threshold for heat damage for squares is equal to the given temperature.
	         *          new.getThresholdHeatDamageTemperature(scale) == thresholdHeatDamageTemperature
	         * @throws  IllegalArgumentException
	         *          The given temperature is not valid.
	         *          | !isValidThresholdHeatDamageTemperature(thresholdHeatDamageTemperature,scale)
	         * @throws  IllegalArgumentException
	         *          The temperature scale is not valid.
	         *          | !isValidTemperatureScale(scale)
	         */
	        @Raw
	        public abstract void setThresholdHeatDamageTemperature(double thresholdHeatDamageTemperature,Temperature scale); 
	        
	        /**
	         * Checks whether this square can have the given thresholdHeatDamageTemperature as thresholdHeatDamageTemperature.
	         * 
	         * @param	thresholdHeatDamageTemperature
	         *          The temperature in the preferred scale to check.
	         * @param   scale
	         *          The scale in which the temperature is expressed in. 
	         * @return  True if thresholdHeatDamageTemperature is higher then the threshold for cold damage.
	         *          | result == (thresholdHeatDamageTemperature > getThresholdColdDamageTemperature(scale))
	         */
	        @Raw
	        public abstract boolean isValidThresholdHeatDamageTemperature(double thresholdHeatDamageTemperature,Temperature scale) ;
	        
	        /**
	         * Returns the threshold for cold damage in the preferred scale for squares.
	         * 
	         * @param 	scale
	         *          The scale in which the temperature is expressed in.
	         */
	        @Basic @Raw
	        public abstract double getThresholdColdDamageTemperature(Temperature scale) ;
	        
	        /**
	         * Variable referencing the threshold for cold damage in degrees Celcius for squares.
	         */
	        public static final double thresholdColdDamageTemperature = -5;
	        
	        /**
	         * Returns the increment size based on the preferred temperature scale for squares.
	         * 
	         * @param  	scale
	         *          The temperature scale in which the increment size has to be calculated.
	         */
	        @Basic @Raw
	        public abstract double getIncrementSizeHeatDamage(Temperature scale) ;
	        
	        /**
	         * Sets the increment size for heat damage.
	         * 
	         * @param	incrementSizeHeatDamage
	         *          The increment size to set as increment size for heat damage.
	         * @param   scale
	         *          the temperature scale in which the increment size is given.
	         * @post    The increment size for heat damage is equal to the given increment size for heat damage.
	         *          | new.getIncrementSizeHeatDamage == incrementSizeHeatDamage()
	         * @throws  IllegalArgumentException
	         *          The given increment size is not valid.
	         *          | !(isValidIncrementSizeHeatDamage())
	         * @throws  IllegalArgumentException
	         *          The temperature scale is not valid.
	         *          | !isValidTemperatureScale(scale)
	         */
	        @Raw
	        public abstract void setIncrementSizeHeatDamage(double incrementSizeHeatDamage,Temperature scale); 
	        
	        /**
	         * Checks if squares can have the given incrementSizeHeatDamage as incrementSizeHeatDamage.
	         * 
	         * @param 	incrementSizeHeatDamage
	         *          The increment size to check.
	         * @return  True if incrementSizeHeatDamage is higher then zero.
	         *          | result == incrementSizeHeatDamage > 0
	         */
	        @Raw
	        public abstract boolean isValidIncrementSizeHeatDamage(double incrementSizeHeatDamage);
	        
	        /**
	         * Calculates the heat damage due the temperature of this square.
	         * 
	         * @return	zero if the temperature is lower then the threshold temperature for heat damage.
	         *          | if(getTemperature(Temperature.CELCIUS) <= getThresholdHeatDamageTemperature(Temperature.CELCIUS))
	         *          |       then result == 0;
	         * @return  the heat damage of this square, this is calculated by following expression:
	         *          	if the temperature of this square is higher then the threshold for heat damage
	         *              then the result is the absolute value of the temperature minus the absolute temperature of
	         *              the threshold temperature for heat damage and this divided by the increment size for heat damage.
	         *              The heat damage is also adjusted upwards.
	         *      	| if(getTemperature(Temperature.CELCIUS) > getThresholdHeatDamageTemperature(Temperature.CELCIUS))
	         *          |       then result == 
	         *          |       	(Math.abs(getTemperature(Temperature.CELCIUS))
	         *         	|               - Math.abs(getThresholdHeatDamageTemperature(Temperature.CELCIUS)))/getIncrementSizeHeatDamage()
	         */
	        public abstract int calculateHeatDamage() ;
	        
	        /**
	         * Calculates the cold damage due the temperature of this square.
	         * 
	         * @return	zero if the temperature is higher then the threshold temperature
	         *          for cold damage.
	         *          | if(getTemperature(Temperature.CELCIUS) >= -5)
	         *          |       then result == 0;
	         * @return  The cold damage of this square, this is calculated by following expression:
	         *          	if the temperature of this square is lower then the threshold for cold damage
	         *              then the result is the absolute value of the temperature of this square minus
	         *              the absolute value of the threshold temperature for cold damage and this divided by
	         *              ten.
	         *      	| if(getTemperature(Temperature.CELCIUS) < -5)
	         *          |       then result == 
	         *          |       	( Math.abs(getTemperature(Temperature.CELCIUS)
	         *          |               - Math.abs(getThresholdColdDamageTemperature(Temperature.CELCIUS)))/10)
	         */
	        public abstract int calculateColdDamage() ;

	        /**
	         * Sets if this square is made of slippery material.
	         * 
	         * @param	madeOfSlipperyMaterial
	         *          Boolean if this square is made of slippery material.
	         * @post    The boolean if this square is made of slippery material of this square 
	         *          is equal to the given boolean.
	         *          | new.ismadeOfSlipperyMaterial() == madeOfSlipperyMaterial
	         */
	        @Raw
	        public abstract void setMadeOfSlipperyMaterial(boolean madeOfSlipperyMaterial) ;
	        
	        /**
	         * Returns if this square is made of slippery material.
	         */
	        @Basic @Raw
	        public abstract boolean isMadeOfSlipperyMaterial() ;
	        
	        /**
	         * Calculates if the floor is slippery
	         * 
	         * @return	True if one of the following cases happens:
	         *          	* the floor is made of slippery material
	         *              * the floor is slippery due humidity and temperature.
	         *       	| result == isMadeOfSlipperyMaterial() || isSlipperyDueCircumstances()
	         */
	        public abstract boolean isSlippery();
	        
	        /**
	         * Calculates if the floor is slippery.
	         * 
	         * @return	True if one of the following cases happens:
	         *              * the temperature is above zero degrees Celcius and the humidity is 100%.
	         *            	* the temperature is below ore equal to zero degrees Celcius
	         *         		  and the humidity is above 10%.
	         *          | if(getTemperature(Temperature.CELCIUS) > 0) && (getHumidity() == 100))
	         *          |       then result == true
	         *          | else if((getTemperature(Temperature.CELCIUS) <= 0) && (getHumidity() > 10))
	         *          |       then result == true
	         *          | else
	         *          |       result == false
	         */
	        public abstract boolean isSlipperyDueCircumstances() ;
	        
	        /**
	         * Calculates the inhabitability of this square.
	         * 
	         * @return	The value for inhabitability, which is calculated by following expression:
	         *          	The root of the third power of the heat damage,
	         *              divided by the root of 101 minus the humidity, this whole part
	         *              then added with the root of cold damage.
	         *              That result multiplied with minus one is the final result
	         *     		| result == -Math.sqrt(getHeatDamage()^3)/Math.sqrt(101-getHumidity()) 
	         *          |         		- Math.sqrt(calculateColdDamage()) 
	         */
	        public abstract double calculateInhabitability() ;
	        
	        /**
	         * Removes one or more borders of this square.
	         * 
	         * @param	directions
	         *          the directions in which the borders have to be removed.
	         * @post    The borders in given directions are removed.
	         *          | new.hasBorder(direction(s)) == false
	         */
	        @Raw
	        public abstract void removeBorders(Direction... directions) ; 
	        
	        /**
	         * method which checks whether an existing border in the given direction can be removed 
	         * 
	         * @param 	direction
	         *   		The direction in which we want to check if the border is removable      
	         * @return  returns a boolean (true) if the border in the direction is removable
	         *          | if( direction == null || !hasBorder(direction) || (borders.size() == 1))
	         *          |    result == false;
	         */
	        @Raw
	        public abstract boolean canBeRemoved(Direction direction);
	        
	        /**
	         * Returns if this square has a border at the given direction.
	         * 
	         * @param	direction
	         *          The direction to check if there is a border.
	         * @return  True if this square has a border at the given direction, and the direction is valid.
	         * 			|if(isValidDirection(direction))
	         *          | 	getBorders().contains(a border)
	         * @post	This method invokes the method square.checkBorders()
	         * 			| this.checkBorders()
	         */
	        @Raw
	        public abstract boolean hasBorder(Direction direction) ;
	        
	        /**
	         * Checks if all borders have an obstacle.
	         * If not the border will be removed.
	         * 
	         * @post	If border has null-object as obstacle, the border
	         * 			will be removed.
	         * 			| for each(border in getBorders())
	         * 			| 		if(border.getObstacle() == null)
	         * 			|			getBorders.contains(border) == false
	         */
	        public abstract void checkBorders() ;
	        
	        /**
	         * Returns the borders of this square.
	         */
	        @Basic @Raw
	        public abstract List<Border> getBorders() ;
	        
	        /**
	         * Returns the border in given direction.
	         * 
	         * @param	direction
	         *          The direction in which we want to get the border.
	         * @return  The method returns the border in the demanded direction, if it has one.
	         *          | if(hasBorder(Direction))
	         *          | result.getDirection() == direction. 
	         * @return  Null if there is no border in the demanded direction.
	         *          | if(!hasBorder(direction))
	         *          | result == null
	         */
	        @Raw
	        public abstract Border getBorder(Direction direction);
	        
	        /**
	         * this method changes an existing border with an other valid border.
	         * @param	border
	         * 			the new border we wish to set.
	         * @Post	the border is set, if it can replace the existing border, and is not null
	         * 			|	if( border != null && getBorder( border.getDirection()) == null
	         * 			|										 && canAddBorder(border))
	         * 			|  getBorder(border.Direction()) == border
	         */
	        @Raw
	        public abstract void modifyBorder(Border border)  ;
	        
	        /**
	         * Add a border to this square.
	         * 
	         * @param	borders
	         *          The borders which has to be set.
	         * @post	If the border can be added, it will be.
	         *          | if(canAddBorder(direction))
	         *          |       then new.getBorder(direction(s)) == border(s) ;
	         */
	        @Raw
	        public abstract void addBorders(Border... borders); 
	        
	        /**
	         * Method which checks whether it is possible to add a given border in a given direction
	         * 
	         * @param	border
	         *          The border we want to check if it could be added.
	         * @return  True if the border can be added, this occurs when neither the direction, 
	         *          and border are null (the border is valid) and the square does not 
	         *          contain a border in the given direction, above that border and square can't be
	         *          terminated. 
	         *          Also the square cannot contain more then 3 doors.
	         *          | if( (!hasBorder(border.getDirection)) && (#WallWithDoors < 3 )
	         *          |					&&canHaveAsBorder(border)&& (!border.isTerminated())
	         *          						&& !hasNeigbour(border.getDirection()))
	         *          |	result == true;
	         */
	        @Raw
	        public abstract boolean canAddBorder(Border border);
	        
	        /**
	         * verifies the consistency between the square and the border.
	         * @param	direction
	         * 			The direction in which we want to check the consistency.	
	         * @return	The border is proper if the direction is valid, 
	         * 			it has a border and it can have that border as border
	         * 			or it has no border and the border is null.
	         * 			|	if(isValidDirection(direction)){
	         *	 	    |  		if (hasBorder(direction))
	         *      	|			result = ( canHaveAsBorder(getBorder(direction)) 	
	         *      	|			&& (this.getBorder(direction).getSquare() == this));
	         *      	|		if ( !hasBorder(direction))
	         *       	|			result = (this.getBorder(direction) == null);
	         *			|			}
	         *      	|	result == false;
	         */
	        @Raw
	        public abstract boolean hasProperBorder(Direction direction);
	 
			/**
	         * checks if a square could potentially have the border.
	         * @param	border	
	         * 			the border we check.
	         * @return	returns true if the square can have the border, this occurs when 
	         * 			the square is terminated and the border is null
	         * 			| 	if (this.isTerminated() )
	         * 			|		result = border == null.
	         * @return	False if border is a null-object or obstacle of border is null-object,
	         * 			else true.
	         * 			| if(border == null || border.getObstacle() == null)
	         * 			|	result == false
	         * 			| else
	         * 			|	result = true
	         */
	        @Raw
	        public abstract boolean canHaveAsBorder(Border border) ;
	        
	        /**
	         * Returns the constant for weighted average for temperatures for squares.
	         */
	        @Basic @Raw
	        public abstract double getConstantForWeightedAverageOfTemperature() ;
	        
	        /**
	         * Sets the constant for weighted average for temperatures.
	         * 
	         * @param	constantForWeightedAverageOfTemperature
	         *          The constant to set for weighted average for temperatures.
	         * @post    The constant for weighted average for temperatures is equal to the given constant.
	         *          | new.getConstantForWeightedAverageOfTemperature() == constantForWeightedAverageOfTemperature
	         * @throws  IllegalArgumentException
	         *          The given constant is not valid.
	         *          | !isValidConstantForWeightedAverageOfTemperature(constantForWeightedAverageOfTemperature)
	         */
	        @Raw
	        public abstract void setConstantForWeightedAverageOfTemperature(double constantForWeightedAverageOfTemperature) ;
	        
	        /**
	         * Checks if squares can have the given constant as constant for weighted average for temperatures.
	         * 
	         * @param	constantForWeightedAverageOfTemperature
	         *          The constant to check.
	         * @return  True if constantForWeightedAverageOfTemperature is lower or equal to 0.4 or 
	         *          constantForWeightedAverageOfTemperature is higher or equal to 0.1
	         *          | result = ((constantForWeightedAverageOfTemperature >= 0.1) 
	         *          |               && (constantForWeightedAverageOfTemperature <= 0.4))
	         */
	        @Raw
	        public abstract boolean isValidConstantForWeightedAverageOfTemperature(double constantForWeightedAverageOfTemperature) ;
	        
	        /**
	         * Merges the given square with this square in given direction.
	         * 
	         * @param	square
	         *          The square to be merged with.
	         * @param   direction
	         *          The direction in which the squares are merged.
	         * @post    In both squares, there is no border in the given direction.
	         *          | new.getBorder(direction) == (new square).getBorder(direction) == false
	         * @post    The new humidity in the given square and this is equal to the average
	         *          of the two squares.
	         *          | new.getHumidity() == calculateAverage(getHumidity(),square.getHumidity())
	         *          | (new square).getHumidity() == calculateAverage(getHumidity(),square.getHumidity())
	         * @post    The new temperature in the given square and this is equal
	         *          to the weighted average of the two squares.
	         *          | new.getTemperature() == calculateWeightedAverage(getTemperature,square.getTemperature()
	         *          | (new square).getTemperature() == calculateWeightedAverage(getTemperature,square.getTemperature()
	         * @throws  IllegalArgumentException
	         *          square is non effective.
	         *          | square == null
	         * @throws  IllegalArgumentException
	         *          direction is non effective.
	         *          | direction == null
	         */
	        public abstract void mergeWith(SquareInterface square, Direction direction);
	        
	        /**
	         * Calculates the average of the two given numbers.
	         * 
	         * @param 	numberOne
	         *          The first number of the two involved in the calculation.
	         * @param   numberTwo
	         *          The second number of the two involved in the calculation.
	         * @return  The average of the two numbers
	         *          | result == (numberOne + numberTwo)/2
	         */
	        @Raw
	        public abstract double calculateAverage(double numberOne,double numberTwo) ;
	        
	        /**
	         * Calculates the weighted average of the two given numbers.
	         * 
	         * @param	numberOne
	         *          The first number of the two involved in the calculation.
	         * @param   numberTwo
	         *          The second number of the two involved in the calculation.
	         * @return  The result is weightOne multiplied by numberOne plus weightTwo multiplied by numberTwo
	         *          and then divided by two.
	         *          The weights are calculated by the methods calculateWeight().
	         *          | let
	         *          |       average == calculateAverage(numberOne,numberTwo)
	         *          |       weightOne == calculateWeight(numberOne,average)
	         *          |       weightTwo == calculateWeight(numberTwo,average)
	         *          | in result == (average*numberOne + weightTwo*numberTwo)2
	         */
	        @Raw
	        public abstract double calculateWeightedAverage(double numberOne,double numberTwo) ;
	        
	        /**
	         * Calculates the weight for a weighted average.
	         * 
	         * @param	number
	         *          Number for which the weight is calculated.
	         * @param   average
	         *          The average of the numbers which are involved
	         *          in the weighted average.
	         * @return  The result is one minus the constant for weighted average of temperature
	         *          multiplied with the number and divided by average and then added with
	         *          the constant for weighted average of temperature.
	         *          | result == (1-getConstantForWeightedAverageOfTemperature())*number/average
	         *          |			+ getConstantForWeightedAverageOfTemperature()
	         */
	        @Raw
	        public abstract double calculateWeight(double number,double average) ;
	        
	        /**
	         * removes borders in the given directions
	         * 
	         * @param 	directions
	         * 			the directions in which to remove a border.
	         * @post	there is no more neigbour in the demanded directions
	         * 			|	new.hasNeighbour( each direction) == false; 
	         */
	        @Raw
	        public abstract void removeNeighbour(Direction... directions);
	        
	        /**
	         * sets a neigbour in  given directions.
	         * 	
	         * @param 	directions
	         * 			the directions we wish to set a neigbour.
	         * @post 	a neigbour is set in the given directions.
	         * 			|new.hasNeighbour( each direction) == true;	
	         */
	        @Raw
	        public abstract void setNeighbour(Direction directions, SquareInterface square);
	       
	        /**
	         * method returning the neighbour of a square in the demanded direction, if any.
	         * @param 	direction
	         * 			| The direction in which we wish to find a neighbour.
	         * @return	the neighbouring square if any, null in the other case.
	         * 			| if (hasNeighbour( direction) 
	         * 			| result == neighbours.get(direction);
	         */
	        public SquareInterface getNeighbour(Direction direction);
	        
	        /**
	         * method checking if there is a neighbour in a given direction.
	         * @param 	direction
	         * 			the direction to check
	         * @return	the boolean whether or not there is a neighbour.
	         * 			|	result = neigbours.contains(direction)
	         */
	        @Raw
	        public abstract boolean hasNeighbour(Direction direction);
	        
	        /**
	         * checks whether or not a neighbour can be added in the direction
	         * 
	         * @param 	direction
	         * 			|	the direction to check.
	         * @return	a neighbour can be added, if non exist in the given direction.
	         * 			|	!hasNeighbour(direction).
	         */
	        @Raw
	        public abstract boolean canAddNeighbour(Direction direction);
	        
	        /**
	         * checks if a direction is valid
	         * 
	         * @param 	direction		
	         * 			the direction to check.
	         * @return	has to differ from null, and be either, north, south, east, west, ceiling, floor.
	         * 			| result = (direction!= null && ( direction.equals(Direction.NORTH) 
	        			|	|| direction.equals(Direction.SOUTH)
	        			|	||direction.equals(Direction.CEILING) || direction.equals(Direction.FLOOR)
	        			|	|| direction.equals(Direction.WEST) || direction.equals(Direction.EAST)));
	         */
	        @Raw
	        public abstract boolean isValidDirection(Direction direction);
	        
	        /**
	         * a method which generates a list of all the direct (with direct we assume squares to which the avatar could move in one step)
	         *  possible destinations of a square. (neighbours which are not blocked by a wall, teleportdestinations ect...).
	         * @return	a list of all possible direct destinations is given.
	         * 			| List<SquareInterface> destinations;
	         * 			|	 for( Direction direction : neighbours.keySet())
	         * 			|		if(!thishasBorder(direction) || (this.hasBorder(direction) && this.getBorder(direction).getObstacle() != wall))
	         * 			|		 	destinations.add(this.getNeighbours(direction))
	         * 			|	 for (SquareInterface destination: getSpecialDestinations())
	         * 			|			destinations.add(destination);
	         * 			|	 result = destinations
	         */
	        public abstract List<SquareInterface> getDirectDestinations();
	        
	        /**
	         * method returning other direct destinations, which could vary from subclass to subclass.
	         * @return	other special direct destinations.
	         * 			|	varies from subclass to sublclass.
	         */
	        public abstract List<SquareInterface> getSpecialDestinations();
	        
	        /**
	         * Method checking if a given square can be reached, starting from this square.
	         * 
	         * @param 	square
	         * 			The square we wish to check whether or not it can be reached.
	         * @param 	beenThere
	         * 			A list of previous squares where we have been already. If the method is invoked by human,
	         * 			the list has to be an empty list. If not, an empty list is created.
	         * @return	True if an interconnection of several direct destinations lead to the given square.
	         * 			|		Boolean reachable = false;
	         * 			|		if( this == square)
	         * 			|			result == true
	         * 			|		if( beenThere.contains(this))
	         * 			|			result == false
	         * 			|
	         * 			|		beenThere.contains(this) == true	
	         * 			|		
	         * 			|		for( SquareInterface destination : this.getDestinations())
	         * 			|				reachable = reachable || destination.canReach(square);
	         * 			|		result == reachable; 
	         */
	        public abstract boolean canReach(SquareInterface square, List<SquareInterface> beenThere);
}